Statistics
| Branch: | Tag: | Revision:

root / image_creator / kamaki_wrapper.py @ c71f38be

History | View | Annotate | Download (6.5 kB)

1 121f3bc0 Nikos Skalkotos
# -*- coding: utf-8 -*-
2 121f3bc0 Nikos Skalkotos
#
3 40e7a487 Nikos Skalkotos
# Copyright 2012 GRNET S.A. All rights reserved.
4 40e7a487 Nikos Skalkotos
#
5 40e7a487 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
6 40e7a487 Nikos Skalkotos
# without modification, are permitted provided that the following
7 40e7a487 Nikos Skalkotos
# conditions are met:
8 40e7a487 Nikos Skalkotos
#
9 40e7a487 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
10 40e7a487 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
11 40e7a487 Nikos Skalkotos
#      disclaimer.
12 40e7a487 Nikos Skalkotos
#
13 40e7a487 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
14 40e7a487 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
15 40e7a487 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
16 40e7a487 Nikos Skalkotos
#      provided with the distribution.
17 40e7a487 Nikos Skalkotos
#
18 40e7a487 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 40e7a487 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 40e7a487 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 40e7a487 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 40e7a487 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 40e7a487 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 40e7a487 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 40e7a487 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 40e7a487 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 40e7a487 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 40e7a487 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 40e7a487 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
30 40e7a487 Nikos Skalkotos
#
31 40e7a487 Nikos Skalkotos
# The views and conclusions contained in the software and
32 40e7a487 Nikos Skalkotos
# documentation are those of the authors and should not be
33 40e7a487 Nikos Skalkotos
# interpreted as representing official policies, either expressed
34 40e7a487 Nikos Skalkotos
# or implied, of GRNET S.A.
35 40e7a487 Nikos Skalkotos
36 121f3bc0 Nikos Skalkotos
"""This modules provides the interface for working with the ./kamaki library.
37 121f3bc0 Nikos Skalkotos
The library is used to upload images to and register them with a Synnefo
38 121f3bc0 Nikos Skalkotos
deployment.
39 121f3bc0 Nikos Skalkotos
"""
40 121f3bc0 Nikos Skalkotos
41 40e7a487 Nikos Skalkotos
from os.path import basename
42 40e7a487 Nikos Skalkotos
43 3dfe3651 Nikos Skalkotos
from kamaki.cli.config import Config
44 997ac76a Nikos Skalkotos
from kamaki.clients import ClientError
45 40e7a487 Nikos Skalkotos
from kamaki.clients.image import ImageClient
46 997ac76a Nikos Skalkotos
from kamaki.clients.pithos import PithosClient
47 31160dc8 Nikos Skalkotos
from kamaki.clients.astakos import AstakosClient
48 40e7a487 Nikos Skalkotos
49 40e7a487 Nikos Skalkotos
50 49c07ce3 Nikos Skalkotos
config = Config()
51 49c07ce3 Nikos Skalkotos
52 49c07ce3 Nikos Skalkotos
53 e77e66a9 Nikos Skalkotos
class Kamaki(object):
54 121f3bc0 Nikos Skalkotos
    """Wrapper class for the ./kamaki library"""
55 31160dc8 Nikos Skalkotos
    CONTAINER = "images"
56 cf4f52b6 Nikos Skalkotos
57 24684bbb Nikos Skalkotos
    @staticmethod
58 49c07ce3 Nikos Skalkotos
    def get_default_cloud_name():
59 49c07ce3 Nikos Skalkotos
        """Returns the name of the default cloud"""
60 49c07ce3 Nikos Skalkotos
        clouds = config.keys('cloud')
61 49c07ce3 Nikos Skalkotos
        default = config.get('global', 'default_cloud')
62 49c07ce3 Nikos Skalkotos
        if not default:
63 49c07ce3 Nikos Skalkotos
            return clouds[0] if len(clouds) else ""
64 49c07ce3 Nikos Skalkotos
        return default if default in clouds else ""
65 49c07ce3 Nikos Skalkotos
66 49c07ce3 Nikos Skalkotos
    @staticmethod
67 49c07ce3 Nikos Skalkotos
    def set_default_cloud(name):
68 49c07ce3 Nikos Skalkotos
        """Sets a cloud account as default"""
69 49c07ce3 Nikos Skalkotos
        config.set('global', 'default_cloud', name)
70 49c07ce3 Nikos Skalkotos
        config.write()
71 49c07ce3 Nikos Skalkotos
72 49c07ce3 Nikos Skalkotos
    @staticmethod
73 49c07ce3 Nikos Skalkotos
    def get_clouds():
74 49c07ce3 Nikos Skalkotos
        """Returns the list of available clouds"""
75 49c07ce3 Nikos Skalkotos
        names = config.keys('cloud')
76 49c07ce3 Nikos Skalkotos
77 49c07ce3 Nikos Skalkotos
        clouds = {}
78 49c07ce3 Nikos Skalkotos
        for name in names:
79 49c07ce3 Nikos Skalkotos
            clouds[name] = config.get('cloud', name)
80 49c07ce3 Nikos Skalkotos
81 49c07ce3 Nikos Skalkotos
        return clouds
82 49c07ce3 Nikos Skalkotos
83 49c07ce3 Nikos Skalkotos
    @staticmethod
84 49c07ce3 Nikos Skalkotos
    def get_cloud_by_name(name):
85 49c07ce3 Nikos Skalkotos
        """Returns a dict with cloud info"""
86 49c07ce3 Nikos Skalkotos
        return config.get('cloud', name)
87 cf4f52b6 Nikos Skalkotos
88 cf4f52b6 Nikos Skalkotos
    @staticmethod
89 49c07ce3 Nikos Skalkotos
    def save_cloud(name, url, token, description=""):
90 49c07ce3 Nikos Skalkotos
        """Save a new cloud account"""
91 49c07ce3 Nikos Skalkotos
        cloud = {'url': url, 'token': token}
92 49c07ce3 Nikos Skalkotos
        if len(description):
93 49c07ce3 Nikos Skalkotos
            cloud['description'] = description
94 49c07ce3 Nikos Skalkotos
        config.set('cloud', name, cloud)
95 49c07ce3 Nikos Skalkotos
96 49c07ce3 Nikos Skalkotos
        # Make the saved cloud the default one
97 49c07ce3 Nikos Skalkotos
        config.set('global', 'default_cloud', name)
98 cf4f52b6 Nikos Skalkotos
        config.write()
99 cf4f52b6 Nikos Skalkotos
100 cf4f52b6 Nikos Skalkotos
    @staticmethod
101 49c07ce3 Nikos Skalkotos
    def remove_cloud(name):
102 49c07ce3 Nikos Skalkotos
        """Deletes an existing cloud from the Kamaki configuration file"""
103 49c07ce3 Nikos Skalkotos
        config.remove_option('cloud', name)
104 49c07ce3 Nikos Skalkotos
        config.write()
105 49c07ce3 Nikos Skalkotos
106 49c07ce3 Nikos Skalkotos
    @staticmethod
107 49c07ce3 Nikos Skalkotos
    def create_account(url, token):
108 49c07ce3 Nikos Skalkotos
        """Given a valid (URL, tokens) pair this method returns an Astakos
109 49c07ce3 Nikos Skalkotos
        client instance
110 49c07ce3 Nikos Skalkotos
        """
111 49c07ce3 Nikos Skalkotos
        client = AstakosClient(url, token)
112 31160dc8 Nikos Skalkotos
        try:
113 49c07ce3 Nikos Skalkotos
            client.authenticate()
114 49c07ce3 Nikos Skalkotos
        except ClientError:
115 49c07ce3 Nikos Skalkotos
            return None
116 49c07ce3 Nikos Skalkotos
117 49c07ce3 Nikos Skalkotos
        return client
118 49c07ce3 Nikos Skalkotos
119 49c07ce3 Nikos Skalkotos
    @staticmethod
120 49c07ce3 Nikos Skalkotos
    def get_account(cloud_name):
121 49c07ce3 Nikos Skalkotos
        """Given a saved cloud name this method returns an Astakos client
122 49c07ce3 Nikos Skalkotos
        instance
123 49c07ce3 Nikos Skalkotos
        """
124 49c07ce3 Nikos Skalkotos
        cloud = config.get('cloud', cloud_name)
125 49c07ce3 Nikos Skalkotos
        assert cloud, "cloud: `%s' does not exist" % cloud_name
126 49c07ce3 Nikos Skalkotos
        assert 'url' in cloud, "url attr is missing in %s" % cloud_name
127 49c07ce3 Nikos Skalkotos
        assert 'token' in cloud, "token attr is missing in %s" % cloud_name
128 49c07ce3 Nikos Skalkotos
129 49c07ce3 Nikos Skalkotos
        return Kamaki.create_account(cloud['url'], cloud['token'])
130 cf4f52b6 Nikos Skalkotos
131 31160dc8 Nikos Skalkotos
    def __init__(self, account, output):
132 88f83027 Nikos Skalkotos
        """Create a Kamaki instance"""
133 997ac76a Nikos Skalkotos
        self.account = account
134 e77e66a9 Nikos Skalkotos
        self.out = output
135 40e7a487 Nikos Skalkotos
136 49c07ce3 Nikos Skalkotos
        self.pithos = PithosClient(
137 49c07ce3 Nikos Skalkotos
            self.account.get_service_endpoints('object-store')['publicURL'],
138 49c07ce3 Nikos Skalkotos
            self.account.token,
139 49c07ce3 Nikos Skalkotos
            self.account.user_info()['id'],
140 37d581b8 Nikos Skalkotos
            self.CONTAINER)
141 40e7a487 Nikos Skalkotos
142 49c07ce3 Nikos Skalkotos
        self.image = ImageClient(
143 49c07ce3 Nikos Skalkotos
            self.account.get_service_endpoints('image')['publicURL'],
144 49c07ce3 Nikos Skalkotos
            self.account.token)
145 40e7a487 Nikos Skalkotos
146 b1395967 Nikos Skalkotos
    def upload(self, file_obj, size=None, remote_path=None, hp=None, up=None):
147 b1aea98e Nikos Skalkotos
        """Upload a file to pithos"""
148 3b7d3fc7 Nikos Skalkotos
149 3b7d3fc7 Nikos Skalkotos
        path = basename(file_obj.name) if remote_path is None else remote_path
150 40e7a487 Nikos Skalkotos
151 b1395967 Nikos Skalkotos
        try:
152 49c07ce3 Nikos Skalkotos
            self.pithos.create_container(self.CONTAINER)
153 b1395967 Nikos Skalkotos
        except ClientError as e:
154 b1395967 Nikos Skalkotos
            if e.status != 202:  # Ignore container already exists errors
155 3b7d3fc7 Nikos Skalkotos
                raise e
156 3b7d3fc7 Nikos Skalkotos
157 3b7d3fc7 Nikos Skalkotos
        hash_cb = self.out.progress_generator(hp) if hp is not None else None
158 3b7d3fc7 Nikos Skalkotos
        upload_cb = self.out.progress_generator(up) if up is not None else None
159 3b7d3fc7 Nikos Skalkotos
160 49c07ce3 Nikos Skalkotos
        self.pithos.upload_object(path, file_obj, size, hash_cb, upload_cb)
161 3b7d3fc7 Nikos Skalkotos
162 49c07ce3 Nikos Skalkotos
        return "pithos://%s/%s/%s" % (self.account.user_info()['id'],
163 49c07ce3 Nikos Skalkotos
                                      self.CONTAINER, path)
164 997ac76a Nikos Skalkotos
165 37d581b8 Nikos Skalkotos
    def register(self, name, location, metadata, public=False):
166 ffc64d7c Nikos Skalkotos
        """Register an image with cyclades"""
167 3b7d3fc7 Nikos Skalkotos
168 d3445122 Nikos Skalkotos
        # Convert all metadata to strings
169 d3445122 Nikos Skalkotos
        str_metadata = {}
170 d3445122 Nikos Skalkotos
        for (key, value) in metadata.iteritems():
171 f99fe99d Nikos Skalkotos
            str_metadata[str(key)] = str(value)
172 37d581b8 Nikos Skalkotos
        is_public = 'true' if public else 'false'
173 37d581b8 Nikos Skalkotos
        params = {'is_public': is_public, 'disk_format': 'diskdump'}
174 49c07ce3 Nikos Skalkotos
        return self.image.register(name, location, params, str_metadata)
175 40e7a487 Nikos Skalkotos
176 3afe6b44 Nikos Skalkotos
    def share(self, location):
177 3afe6b44 Nikos Skalkotos
        """Share this file with all the users"""
178 3afe6b44 Nikos Skalkotos
179 49c07ce3 Nikos Skalkotos
        self.pithos.set_object_sharing(location, "*")
180 3afe6b44 Nikos Skalkotos
181 03eb7dc8 Nikos Skalkotos
    def object_exists(self, location):
182 03eb7dc8 Nikos Skalkotos
        """Check if an object exists in pythos"""
183 03eb7dc8 Nikos Skalkotos
184 03eb7dc8 Nikos Skalkotos
        try:
185 49c07ce3 Nikos Skalkotos
            self.pithos.get_object_info(location)
186 03eb7dc8 Nikos Skalkotos
        except ClientError as e:
187 03eb7dc8 Nikos Skalkotos
            if e.status == 404:  # Object not found error
188 03eb7dc8 Nikos Skalkotos
                return False
189 03eb7dc8 Nikos Skalkotos
            else:
190 03eb7dc8 Nikos Skalkotos
                raise
191 03eb7dc8 Nikos Skalkotos
        return True
192 03eb7dc8 Nikos Skalkotos
193 6152a559 Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :