Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / cyclades / __init__.py @ 75ae8a08

History | View | Annotate | Download (10 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 55faa0bc Stavros Sachtouris
from kamaki.clients.cyclades.rest_api import CycladesRestClient
35 e864cd9e Stavros Sachtouris
from kamaki.clients.network import NetworkClient
36 0e27687b Stavros Sachtouris
from kamaki.clients.utils import path4url
37 6f2b87c1 Stavros Sachtouris
from kamaki.clients import ClientError, Waiter
38 75ae8a08 Giorgos Korfiatis
import json
39 3dabe5d2 Stavros Sachtouris
40 6f2b87c1 Stavros Sachtouris
class CycladesClient(CycladesRestClient, Waiter):
41 76e7661e Stavros Sachtouris
    """Synnefo Cyclades Compute API client"""
42 2f749e6e Stavros Sachtouris
43 dbcbf446 Stavros Sachtouris
    def create_server(
44 dbcbf446 Stavros Sachtouris
            self, name, flavor_id, image_id,
45 75ae8a08 Giorgos Korfiatis
            metadata=None, personality=None, networks=None, project=None):
46 dbcbf446 Stavros Sachtouris
        """Submit request to create a new server
47 dbcbf446 Stavros Sachtouris

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

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

52 2bd23362 Stavros Sachtouris
        :param image_id: (str) id denoting the OS image to run on virt. server
53 dbcbf446 Stavros Sachtouris

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

56 dbcbf446 Stavros Sachtouris
        :param personality: a list of (file path, file contents) tuples,
57 2bd23362 Stavros Sachtouris
            describing files to be injected into virtual server upon creation
58 dbcbf446 Stavros Sachtouris

59 264a13f7 Stavros Sachtouris
        :param networks: (list of dicts) Networks to connect to, list this:
60 264a13f7 Stavros Sachtouris
            "networks": [
61 de329b4c Stavros Sachtouris
            {"uuid": <network_uuid>},
62 de329b4c Stavros Sachtouris
            {"uuid": <network_uuid>, "fixed_ip": address},
63 de329b4c Stavros Sachtouris
            {"port": <port_id>}, ...]
64 eb647cfe Stavros Sachtouris
            ATTENTION: Empty list is different to None. None means ' do not
65 eb647cfe Stavros Sachtouris
            mention it', empty list means 'automatically get an ip'
66 264a13f7 Stavros Sachtouris

67 75ae8a08 Giorgos Korfiatis
        :param project: the project where to assign the server
68 75ae8a08 Giorgos Korfiatis

69 2bd23362 Stavros Sachtouris
        :returns: a dict with the new virtual server details
70 dbcbf446 Stavros Sachtouris

71 dbcbf446 Stavros Sachtouris
        :raises ClientError: wraps request errors
72 dbcbf446 Stavros Sachtouris
        """
73 dbcbf446 Stavros Sachtouris
        image = self.get_image_details(image_id)
74 dbcbf446 Stavros Sachtouris
        metadata = metadata or dict()
75 dbcbf446 Stavros Sachtouris
        for key in ('os', 'users'):
76 dbcbf446 Stavros Sachtouris
            try:
77 dbcbf446 Stavros Sachtouris
                metadata[key] = image['metadata'][key]
78 dbcbf446 Stavros Sachtouris
            except KeyError:
79 dbcbf446 Stavros Sachtouris
                pass
80 dbcbf446 Stavros Sachtouris
81 65a8b1da Stavros Sachtouris
        return super(CycladesClient, self).create_server(
82 65a8b1da Stavros Sachtouris
            name, flavor_id, image_id,
83 75ae8a08 Giorgos Korfiatis
            metadata=metadata, personality=personality, networks=networks,
84 75ae8a08 Giorgos Korfiatis
            project=project)
85 dbcbf446 Stavros Sachtouris
86 c75be81a Stavros Sachtouris
    def set_firewall_profile(self, server_id, profile, port_id):
87 c75be81a Stavros Sachtouris
        """Set the firewall profile for the public interface of a server
88 c75be81a Stavros Sachtouris
        :param server_id: integer (str or int)
89 c75be81a Stavros Sachtouris
        :param profile: (str) ENABLED | DISABLED | PROTECTED
90 c75be81a Stavros Sachtouris
        :param port_id: (str) This port must connect to a public network
91 c75be81a Stavros Sachtouris
        :returns: (dict) response headers
92 c75be81a Stavros Sachtouris
        """
93 c75be81a Stavros Sachtouris
        req = {'firewallProfile': {'profile': profile, 'nic': port_id}}
94 c75be81a Stavros Sachtouris
        r = self.servers_action_post(server_id, json_data=req, success=202)
95 c75be81a Stavros Sachtouris
        return r.headers
96 c75be81a Stavros Sachtouris
97 a1c50326 Giorgos Verigakis
    def start_server(self, server_id):
98 f5eac743 Stavros Sachtouris
        """Submit a startup request
99 f5eac743 Stavros Sachtouris

100 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
101 cd295a1d Stavros Sachtouris

102 cd295a1d Stavros Sachtouris
        :returns: (dict) response headers
103 f5eac743 Stavros Sachtouris
        """
104 6a0b1658 Giorgos Verigakis
        req = {'start': {}}
105 ef2e6c9f Stavros Sachtouris
        r = self.servers_action_post(server_id, json_data=req, success=202)
106 cd295a1d Stavros Sachtouris
        return r.headers
107 6f1ec797 Stavros Sachtouris
108 a1c50326 Giorgos Verigakis
    def shutdown_server(self, server_id):
109 f5eac743 Stavros Sachtouris
        """Submit a shutdown request
110 f5eac743 Stavros Sachtouris

111 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
112 cd295a1d Stavros Sachtouris

113 cd295a1d Stavros Sachtouris
        :returns: (dict) response headers
114 f5eac743 Stavros Sachtouris
        """
115 6a0b1658 Giorgos Verigakis
        req = {'shutdown': {}}
116 ef2e6c9f Stavros Sachtouris
        r = self.servers_action_post(server_id, json_data=req, success=202)
117 cd295a1d Stavros Sachtouris
        return r.headers
118 3dabe5d2 Stavros Sachtouris
119 a1c50326 Giorgos Verigakis
    def get_server_console(self, server_id):
120 f5eac743 Stavros Sachtouris
        """
121 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
122 f5eac743 Stavros Sachtouris

123 2bd23362 Stavros Sachtouris
        :returns: (dict) info to set a VNC connection to virtual server
124 f5eac743 Stavros Sachtouris
        """
125 6a0b1658 Giorgos Verigakis
        req = {'console': {'type': 'vnc'}}
126 ef2e6c9f Stavros Sachtouris
        r = self.servers_action_post(server_id, json_data=req, success=200)
127 6a0b1658 Giorgos Verigakis
        return r.json['console']
128 2d67ecbb Stavros Sachtouris
129 75ae8a08 Giorgos Korfiatis
    def reassign_server(self, server_id, project):
130 75ae8a08 Giorgos Korfiatis
        req = {'reassign': {'project': project}}
131 75ae8a08 Giorgos Korfiatis
        r = self.servers_action_post(server_id, json_data=req, success=200)
132 75ae8a08 Giorgos Korfiatis
        return r.headers
133 75ae8a08 Giorgos Korfiatis
134 a1c50326 Giorgos Verigakis
    def get_server_stats(self, server_id):
135 f5eac743 Stavros Sachtouris
        """
136 f5eac743 Stavros Sachtouris
        :param server_id: integer (str or int)
137 f5eac743 Stavros Sachtouris

138 f5eac743 Stavros Sachtouris
        :returns: (dict) auto-generated graphs of statistics (urls)
139 f5eac743 Stavros Sachtouris
        """
140 e51c7d5b Stavros Sachtouris
        r = self.servers_stats_get(server_id)
141 6a0b1658 Giorgos Verigakis
        return r.json['stats']
142 3dabe5d2 Stavros Sachtouris
143 b45834eb Stavros Sachtouris
    def get_server_diagnostics(self, server_id):
144 b45834eb Stavros Sachtouris
        """
145 b45834eb Stavros Sachtouris
        :param server_id: integer (str or int)
146 b45834eb Stavros Sachtouris

147 b45834eb Stavros Sachtouris
        :returns: (list)
148 b45834eb Stavros Sachtouris
        """
149 b45834eb Stavros Sachtouris
        r = self.servers_diagnostics_get(server_id)
150 b45834eb Stavros Sachtouris
        return r.json
151 b45834eb Stavros Sachtouris
152 7b2e4bf1 Stavros Sachtouris
    def wait_server(
153 7b2e4bf1 Stavros Sachtouris
            self, server_id,
154 7b2e4bf1 Stavros Sachtouris
            current_status='BUILD',
155 7b2e4bf1 Stavros Sachtouris
            delay=1, max_wait=100, wait_cb=None):
156 7b2e4bf1 Stavros Sachtouris
        """Wait for server while its status is current_status
157 7b2e4bf1 Stavros Sachtouris

158 7b2e4bf1 Stavros Sachtouris
        :param server_id: integer (str or int)
159 7b2e4bf1 Stavros Sachtouris

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

162 7b2e4bf1 Stavros Sachtouris
        :param delay: time interval between retries
163 7b2e4bf1 Stavros Sachtouris

164 c788a761 Stavros Sachtouris
        :max_wait: (int) timeout in secconds
165 c788a761 Stavros Sachtouris

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

168 7b2e4bf1 Stavros Sachtouris
        :returns: (str) the new mode if succesfull, (bool) False if timed out
169 7b2e4bf1 Stavros Sachtouris
        """
170 7b2e4bf1 Stavros Sachtouris
171 7b2e4bf1 Stavros Sachtouris
        def get_status(self, server_id):
172 7b2e4bf1 Stavros Sachtouris
            r = self.get_server_details(server_id)
173 7b2e4bf1 Stavros Sachtouris
            return r['status'], (r.get('progress', None) if (
174 7b2e4bf1 Stavros Sachtouris
                            current_status in ('BUILD', )) else None)
175 7b2e4bf1 Stavros Sachtouris
176 7b2e4bf1 Stavros Sachtouris
        return self._wait(
177 7b2e4bf1 Stavros Sachtouris
            server_id, current_status, get_status, delay, max_wait, wait_cb)
178 7b2e4bf1 Stavros Sachtouris
179 e864cd9e Stavros Sachtouris
180 eb647cfe Stavros Sachtouris
class CycladesNetworkClient(NetworkClient):
181 e864cd9e Stavros Sachtouris
    """Cyclades Network API extentions"""
182 e864cd9e Stavros Sachtouris
183 e864cd9e Stavros Sachtouris
    network_types = (
184 e864cd9e Stavros Sachtouris
        'CUSTOM', 'MAC_FILTERED', 'IP_LESS_ROUTED', 'PHYSICAL_VLAN')
185 e864cd9e Stavros Sachtouris
186 0e27687b Stavros Sachtouris
    def list_networks(self, detail=None):
187 0e27687b Stavros Sachtouris
        path = path4url('networks', 'detail' if detail else '')
188 0e27687b Stavros Sachtouris
        r = self.get(path, success=200)
189 0e27687b Stavros Sachtouris
        return r.json['networks']
190 0e27687b Stavros Sachtouris
191 75ae8a08 Giorgos Korfiatis
    def create_network(self, type, name=None, shared=None, project=None):
192 e864cd9e Stavros Sachtouris
        req = dict(network=dict(type=type, admin_state_up=True))
193 e864cd9e Stavros Sachtouris
        if name:
194 e864cd9e Stavros Sachtouris
            req['network']['name'] = name
195 e864cd9e Stavros Sachtouris
        if shared not in (None, ):
196 e864cd9e Stavros Sachtouris
            req['network']['shared'] = bool(shared)
197 75ae8a08 Giorgos Korfiatis
        if project is not None:
198 75ae8a08 Giorgos Korfiatis
            req['network']['project'] = project
199 e864cd9e Stavros Sachtouris
        r = self.networks_post(json_data=req, success=201)
200 e864cd9e Stavros Sachtouris
        return r.json['network']
201 ccdd1b82 Stavros Sachtouris
202 75ae8a08 Giorgos Korfiatis
    def networks_action_post(
203 75ae8a08 Giorgos Korfiatis
            self, network_id='', json_data=None, success=202, **kwargs):
204 75ae8a08 Giorgos Korfiatis
        """POST base_url/networks/<network_id>/action
205 75ae8a08 Giorgos Korfiatis

206 75ae8a08 Giorgos Korfiatis
        :returns: request response
207 75ae8a08 Giorgos Korfiatis
        """
208 75ae8a08 Giorgos Korfiatis
        if json_data:
209 75ae8a08 Giorgos Korfiatis
            json_data = json.dumps(json_data)
210 75ae8a08 Giorgos Korfiatis
            self.set_header('Content-Type', 'application/json')
211 75ae8a08 Giorgos Korfiatis
            self.set_header('Content-Length', len(json_data))
212 75ae8a08 Giorgos Korfiatis
        path = path4url('networks', network_id, 'action')
213 75ae8a08 Giorgos Korfiatis
        return self.post(path, data=json_data, success=success, **kwargs)
214 75ae8a08 Giorgos Korfiatis
215 75ae8a08 Giorgos Korfiatis
    def reassign_network(self, network_id, project):
216 75ae8a08 Giorgos Korfiatis
        req = {'reassign': {'project': project}}
217 75ae8a08 Giorgos Korfiatis
        r = self.networks_action_post(network_id, json_data=req, success=200)
218 75ae8a08 Giorgos Korfiatis
        return r.headers
219 75ae8a08 Giorgos Korfiatis
220 f3740b99 Stavros Sachtouris
    def list_ports(self, detail=None):
221 f3740b99 Stavros Sachtouris
        path = path4url('ports', 'detail' if detail else '')
222 f3740b99 Stavros Sachtouris
        r = self.get(path, success=200)
223 f3740b99 Stavros Sachtouris
        return r.json['ports']
224 f3740b99 Stavros Sachtouris
225 737995ed Stavros Sachtouris
    def create_port(
226 eb647cfe Stavros Sachtouris
            self, network_id,
227 eb647cfe Stavros Sachtouris
            device_id=None, security_groups=None, name=None, fixed_ips=None):
228 b82c93a5 Stavros Sachtouris
        """
229 b82c93a5 Stavros Sachtouris
        :param fixed_ips: (list of dicts) [{"ip_address": IPv4}, ...]
230 b82c93a5 Stavros Sachtouris
        """
231 eb647cfe Stavros Sachtouris
        port = dict(network_id=network_id)
232 eb647cfe Stavros Sachtouris
        if device_id:
233 eb647cfe Stavros Sachtouris
            port['device_id'] = device_id
234 ccdd1b82 Stavros Sachtouris
        if security_groups:
235 ccdd1b82 Stavros Sachtouris
            port['security_groups'] = security_groups
236 737995ed Stavros Sachtouris
        if name:
237 737995ed Stavros Sachtouris
            port['name'] = name
238 56d84a4e Stavros Sachtouris
        if fixed_ips:
239 b82c93a5 Stavros Sachtouris
            for fixed_ip in fixed_ips or []:
240 b82c93a5 Stavros Sachtouris
                if not 'ip_address' in fixed_ip:
241 7a3c66e1 Stavros Sachtouris
                    raise ValueError('Invalid fixed_ip [%s]' % fixed_ip)
242 b7d79306 Stavros Sachtouris
            port['fixed_ips'] = fixed_ips
243 e8ba3e9f Stavros Sachtouris
        r = self.ports_post(json_data=dict(port=port), success=201)
244 ccdd1b82 Stavros Sachtouris
        return r.json['port']
245 6f2b87c1 Stavros Sachtouris
246 67377ec3 Stavros Sachtouris
    def create_floatingip(
247 75ae8a08 Giorgos Korfiatis
            self,
248 75ae8a08 Giorgos Korfiatis
            floating_network_id=None, floating_ip_address='', project_id=None):
249 67377ec3 Stavros Sachtouris
        """
250 67377ec3 Stavros Sachtouris
        :param floating_network_id: if not provided, it is assigned
251 67377ec3 Stavros Sachtouris
            automatically by the service
252 75ae8a08 Giorgos Korfiatis
        :param floating_ip_address: only if the IP is availabel in network pool
253 75ae8a08 Giorgos Korfiatis
        :param project_id: specific project to get resource quotas from
254 67377ec3 Stavros Sachtouris
        """
255 67377ec3 Stavros Sachtouris
        floatingip = {}
256 67377ec3 Stavros Sachtouris
        if floating_network_id:
257 67377ec3 Stavros Sachtouris
            floatingip['floating_network_id'] = floating_network_id
258 67377ec3 Stavros Sachtouris
        if floating_ip_address:
259 67377ec3 Stavros Sachtouris
            floatingip['floating_ip_address'] = floating_ip_address
260 75ae8a08 Giorgos Korfiatis
        if project_id:
261 75ae8a08 Giorgos Korfiatis
            floatingip['project'] = project_id
262 67377ec3 Stavros Sachtouris
        r = self.floatingips_post(
263 67377ec3 Stavros Sachtouris
            json_data=dict(floatingip=floatingip), success=200)
264 67377ec3 Stavros Sachtouris
        return r.json['floatingip']
265 75ae8a08 Giorgos Korfiatis
266 75ae8a08 Giorgos Korfiatis
    def reassign_floating_ip(self, floating_network_id, project_id):
267 75ae8a08 Giorgos Korfiatis
        """Change the project where this ip is charged"""
268 75ae8a08 Giorgos Korfiatis
        path = path4url('floatingips', floating_network_id, 'action')
269 75ae8a08 Giorgos Korfiatis
        json_data = dict(reassign=dict(project=project_id))
270 75ae8a08 Giorgos Korfiatis
        self.post(path, json=json_data, success=202)