Commit eb3ca8ca authored by Giorgos Verigakis's avatar Giorgos Verigakis

Major refactoring

Groundwork to support different APIs (synnefo and
plankton).

New configuration mechanism (kamaki config)
parent fa0fa721
# Copyright 2011 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
__version__ = '0.3'
......@@ -129,8 +129,9 @@ class Client(object):
def _delete(self, path, success=204):
return self._cmd('DELETE', path, None, success)
class ComputeClient(Client):
# Servers
def list_servers(self, detail=False):
......@@ -350,3 +351,9 @@ class Client(object):
path = '/networks/%s/action' % network_id
body = json.dumps({'remove': {'serverRef': server_id}})
self._post(path, body)
class ImagesClient(Client):
def list_public(self, detail=False):
path = '/images/detail' if detail else '/images/'
return self._get(path)
# Copyright 2011 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
import json
import logging
import os
log = logging.getLogger('kamaki.config')
class ConfigError(Exception):
pass
class Config(object):
def __init__(self, path, env, defaults):
self.path = os.environ.get(env, path)
self.defaults = defaults
d = self.read()
for key, val in d.items():
if key not in defaults:
log.warning('Ignoring unknown config key "%s".', key)
self.d = d
self.overrides = {}
def read(self):
if not os.path.exists(self.path):
return {}
with open(self.path) as f:
data = f.read()
try:
d = json.loads(data)
assert isinstance(d, dict)
return d
except (ValueError, AssertionError):
msg = '"%s" does not look like a kamaki config file.' % self.path
raise ConfigError(msg)
def write(self):
self.read() # Make sure we don't overwrite anything wrong
with open(self.path, 'w') as f:
data = json.dumps(self.d, indent=True)
f.write(data)
def items(self):
for key, val in self.defaults.items():
yield key, self.get(key)
def get(self, key):
if key in self.overrides:
return self.overrides[key]
if key in self.d:
return self.d[key]
return self.defaults.get(key)
def set(self, key, val):
if key not in self.defaults:
log.warning('Ignoring unknown config key "%s".', key)
return
self.d[key] = val
self.write()
def delete(self, key):
if key not in self.defaults:
log.warning('Ignoring unknown config key "%s".', key)
return
self.d.pop(key, None)
self.write()
def override(self, key, val):
assert key in self.defaults
if val is not None:
self.overrides[key] = val
This diff is collapsed.
# Copyright 2011 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
class OrderedDict(dict):
"""An ordered dict implementation for Python versions prior to 2.7"""
def __init__(self):
dict.__init__(self)
self._keys = []
def __delitem__(self, key):
dict.__delitem__(self, key)
self._keys.remove(key)
def __iter__(self):
return iter(self._keys)
def __repr__(self):
return repr(self.items())
def __setitem__(self, key, value):
if key not in self:
self._keys.append(key)
dict.__setitem__(self, key, value)
def keys(self):
return self._keys
def iteritems(self):
for key in self._keys:
yield key, self[key]
def items(self):
return list(self.iteritems())
def print_addresses(addresses, margin):
for address in addresses:
if address['id'] == 'public':
net = 'public'
else:
net = '%s/%s' % (address['id'], address['name'])
print '%s:' % net.rjust(margin + 4)
ether = address.get('mac', None)
if ether:
print '%s: %s' % ('ether'.rjust(margin + 8), ether)
firewall = address.get('firewallProfile', None)
if firewall:
print '%s: %s' % ('firewall'.rjust(margin + 8), firewall)
for ip in address.get('values', []):
key = 'inet' if ip['version'] == 4 else 'inet6'
print '%s: %s' % (key.rjust(margin + 8), ip['addr'])
def print_metadata(metadata, margin):
print '%s:' % 'metadata'.rjust(margin)
for key, val in metadata.get('values', {}).items():
print '%s: %s' % (key.rjust(margin + 4), val)
def print_dict(d, exclude=()):
if not d:
return
margin = max(len(key) for key in d) + 1
for key, val in sorted(d.items()):
if key in exclude:
continue
if key == 'addresses':
print '%s:' % 'addresses'.rjust(margin)
print_addresses(val.get('values', []), margin)
continue
elif key == 'metadata':
print_metadata(val, margin)
continue
elif key == 'servers':
val = ', '.join(str(x) for x in val['values'])
print '%s: %s' % (key.rjust(margin), val)
def print_items(items, detail=False):
for item in items:
print '%s %s' % (item['id'], item.get('name', ''))
if detail:
print_dict(item, exclude=('id', 'name'))
print
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment