Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / cyclades.py @ b98fe305

History | View | Annotate | Download (8.9 kB)

1
# Copyright 2011 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from kamaki.clients.cyclades_rest_api import CycladesClientApi
35
from kamaki.clients import ClientError
36
from time import sleep
37

    
38

    
39
class CycladesClient(CycladesClientApi):
40
    """GRNet Cyclades API client"""
41

    
42
    def start_server(self, server_id):
43
        """Submit a startup request
44

45
        :param server_id: integer (str or int)
46
        """
47
        req = {'start': {}}
48
        r = self.servers_post(server_id, 'action', json_data=req, success=202)
49
        r.release()
50

    
51
    def shutdown_server(self, server_id):
52
        """Submit a shutdown request
53

54
        :param server_id: integer (str or int)
55
        """
56
        req = {'shutdown': {}}
57
        r = self.servers_post(server_id, 'action', json_data=req, success=202)
58
        r.release()
59

    
60
    def get_server_console(self, server_id):
61
        """
62
        :param server_id: integer (str or int)
63

64
        :returns: (dict) info to set a VNC connection to VM
65
        """
66
        req = {'console': {'type': 'vnc'}}
67
        r = self.servers_post(server_id, 'action', json_data=req, success=200)
68
        return r.json['console']
69

    
70
    def get_firewall_profile(self, server_id):
71
        """
72
        :param server_id: integer (str or int)
73

74
        :returns: (str) ENABLED | DISABLED | PROTECTED
75

76
        :raises ClientError: 520 No Firewall Profile
77
        """
78
        r = self.get_server_details(server_id)
79
        try:
80
            return r['attachments']['values'][0]['firewallProfile']
81
        except KeyError:
82
            raise ClientError('No Firewall Profile', 520,
83
                details='Server %s is missing a firewall profile' % server_id)
84

    
85
    def set_firewall_profile(self, server_id, profile):
86
        """Set the firewall profile for the public interface of a server
87

88
        :param server_id: integer (str or int)
89

90
        :param profile: (str) ENABLED | DISABLED | PROTECTED
91
        """
92
        req = {'firewallProfile': {'profile': profile}}
93
        r = self.servers_post(server_id, 'action', json_data=req, success=202)
94
        r.release()
95

    
96
    def list_server_nics(self, server_id):
97
        """
98
        :param server_id: integer (str or int)
99

100
        :returns: (dict) network interface connections
101
        """
102
        r = self.servers_get(server_id, 'ips')
103
        return r.json['addresses']['values']
104

    
105
    def get_server_stats(self, server_id):
106
        """
107
        :param server_id: integer (str or int)
108

109
        :returns: (dict) auto-generated graphs of statistics (urls)
110
        """
111
        r = self.servers_get(server_id, 'stats')
112
        return r.json['stats']
113

    
114
    def list_networks(self, detail=False):
115
        """
116
        :param detail: (bool)
117

118
        :returns: (list) id,name if not detail else full info per network
119
        """
120
        detail = 'detail' if detail else ''
121
        r = self.networks_get(command=detail)
122
        return r.json['networks']['values']
123

    
124
    def list_network_nics(self, network_id):
125
        """
126
        :param network_id: integer (str or int)
127

128
        :returns: (list)
129
        """
130
        r = self.networks_get(network_id=network_id)
131
        return r.json['network']['attachments']['values']
132

    
133
    def create_network(self,
134
        name, cidr=None, gateway=None, type=None, dhcp=None):
135
        """
136
        :param name: (str)
137

138
        :param cidr: (str)
139

140
        :param geteway: (str)
141

142
        :param type: (str)
143

144
        :param dhcp: (str)
145

146
        :returns: (dict) network detailed info
147
        """
148
        net = dict(name=name)
149
        if cidr:
150
            net['cidr'] = cidr
151
        if gateway:
152
            net['gateway'] = gateway
153
        if type:
154
            net['type'] = type
155
        if dhcp:
156
            net['dhcp'] = dhcp
157
        req = dict(network=net)
158
        r = self.networks_post(json_data=req, success=202)
159
        return r.json['network']
160

    
161
    def get_network_details(self, network_id):
162
        """
163
        :param network_id: integer (str or int)
164

165
        :returns: (dict)
166
        """
167
        r = self.networks_get(network_id=network_id)
168
        return r.json['network']
169

    
170
    def update_network_name(self, network_id, new_name):
171
        """
172
        :param network_id: integer (str or int)
173

174
        :param new_name: (str)
175
        """
176
        req = {'network': {'name': new_name}}
177
        r = self.networks_put(network_id=network_id, json_data=req)
178
        r.release()
179

    
180
    def delete_network(self, network_id):
181
        """
182
        :param network_id: integer (str or int)
183

184
        :raises ClientError: 421 Network in use
185
        """
186
        try:
187
            r = self.networks_delete(network_id)
188
        except ClientError as err:
189
            if err.status == 421:
190
                err.details =\
191
                'Network may be still connected to at least one server'
192
            raise err
193
        r.release()
194

    
195
    def connect_server(self, server_id, network_id):
196
        """ Connect a server to a network
197

198
        :param server_id: integer (str or int)
199

200
        :param network_id: integer (str or int)
201
        """
202
        req = {'add': {'serverRef': server_id}}
203
        r = self.networks_post(network_id, 'action', json_data=req)
204
        r.release()
205

    
206
    def disconnect_server(self, server_id, nic_id):
207
        """
208
        :param server_id: integer (str or int)
209

210
        :param nic_id: (str)
211
        """
212
        server_nets = self.list_server_nics(server_id)
213
        nets = [(net['id'], net['network_id']) for net in server_nets\
214
            if nic_id == net['id']]
215
        for (nic_id, network_id) in nets:
216
            req = {'remove': {'attachment': unicode(nic_id)}}
217
            r = self.networks_post(network_id, 'action', json_data=req)
218
            r.release()
219

    
220
    def disconnect_network_nics(self, netid):
221
        """
222
        :param netid: integer (str or int)
223
        """
224
        for nic in self.list_network_nics(netid):
225
            req = dict(remove=dict(attachment=nic))
226
            r = self.networks_post(netid, 'action', json_data=req)
227
            r.release()
228

    
229
    def wait_server(self, server_id,
230
        current_status='BUILD',
231
        delay=0.5,
232
        max_wait=128,
233
        wait_cb=None):
234
        """Wait for server while its status is current_status
235

236
        :param server_id: integer (str or int)
237

238
        :param current_status: (str) BUILD|ACTIVE|STOPPED|DELETED|REBOOT
239

240
        :param delay: time interval between retries
241

242
        :param wait_cb: if set a progressbar is used to show progress
243

244
        :returns: (str) the new mode if succesfull, (bool) False if timed out
245
        """
246
        r = self.get_server_details(server_id)
247
        if r['status'] != current_status:
248
            return r['status']
249
        old_wait = total_wait = 0
250

    
251
        if current_status == 'BUILD':
252
            max_wait = 100
253
            wait_gen = wait_cb(max_wait)
254
        elif wait_cb:
255
            wait_gen = wait_cb(1 + max_wait // delay)
256
            wait_gen.next()
257

    
258
        while r['status'] == current_status and total_wait <= max_wait:
259
            if current_status == 'BUILD':
260
                total_wait = int(r['progress'])
261
                if wait_cb:
262
                    for i in range(int(old_wait), int(total_wait)):
263
                        wait_gen.next()
264
                    old_wait = total_wait
265
            else:
266
                if wait_cb:
267
                    wait_gen.next()
268
                total_wait += delay
269
            sleep(delay)
270
            r = self.get_server_details(server_id)
271

    
272
        if r['status'] != current_status:
273
            if wait_cb:
274
                try:
275
                    while True:
276
                        wait_gen.next()
277
                except:
278
                    pass
279
            return r['status']
280
        return False