trunk merged. conflict resolved.

This commit is contained in:
Ilya Alekseyev
2011-04-18 15:25:44 +04:00
36 changed files with 27781 additions and 19076 deletions

View File

@@ -5,13 +5,7 @@ _trial_temp
keys keys
networks networks
nova.sqlite nova.sqlite
CA/cacert.pem CA
CA/crl.pem
CA/index.txt*
CA/openssl.cnf
CA/serial*
CA/newcerts/*.pem
CA/private/cakey.pem
nova/vcsversion.py nova/vcsversion.py
*.DS_Store *.DS_Store
.project .project

View File

@@ -4,6 +4,7 @@
<anotherjesse@gmail.com> <jesse@dancelamb> <anotherjesse@gmail.com> <jesse@dancelamb>
<anotherjesse@gmail.com> <jesse@gigantor.local> <anotherjesse@gmail.com> <jesse@gigantor.local>
<anotherjesse@gmail.com> <jesse@ubuntu> <anotherjesse@gmail.com> <jesse@ubuntu>
<anotherjesse@gmail.com> <jesse@aire.local>
<ant@openstack.org> <amesserl@rackspace.com> <ant@openstack.org> <amesserl@rackspace.com>
<Armando.Migliaccio@eu.citrix.com> <armando.migliaccio@citrix.com> <Armando.Migliaccio@eu.citrix.com> <armando.migliaccio@citrix.com>
<brian.lamar@rackspace.com> <brian.lamar@gmail.com> <brian.lamar@rackspace.com> <brian.lamar@gmail.com>

View File

@@ -31,7 +31,9 @@ Jay Pipes <jaypipes@gmail.com>
Jesse Andrews <anotherjesse@gmail.com> Jesse Andrews <anotherjesse@gmail.com>
Joe Heck <heckj@mac.com> Joe Heck <heckj@mac.com>
Joel Moore <joelbm24@gmail.com> Joel Moore <joelbm24@gmail.com>
Johannes Erdfelt <johannes.erdfelt@rackspace.com>
John Dewey <john@dewey.ws> John Dewey <john@dewey.ws>
John Tran <jtran@attinteractive.com>
Jonathan Bryce <jbryce@jbryce.com> Jonathan Bryce <jbryce@jbryce.com>
Jordan Rinke <jordan@openstack.org> Jordan Rinke <jordan@openstack.org>
Josh Durgin <joshd@hq.newdream.net> Josh Durgin <joshd@hq.newdream.net>
@@ -72,5 +74,6 @@ Trey Morris <trey.morris@rackspace.com>
Tushar Patil <tushar.vitthal.patil@gmail.com> Tushar Patil <tushar.vitthal.patil@gmail.com>
Vasiliy Shlykov <vash@vasiliyshlykov.org> Vasiliy Shlykov <vash@vasiliyshlykov.org>
Vishvananda Ishaya <vishvananda@gmail.com> Vishvananda Ishaya <vishvananda@gmail.com>
Yoshiaki Tamura <yoshi@midokura.jp>
Youcef Laribi <Youcef.Laribi@eu.citrix.com> Youcef Laribi <Youcef.Laribi@eu.citrix.com>
Zhixue Wu <Zhixue.Wu@citrix.com> Zhixue Wu <Zhixue.Wu@citrix.com>

11
CA/.gitignore vendored
View File

@@ -1,11 +0,0 @@
index.txt
index.txt.old
index.txt.attr
index.txt.attr.old
cacert.pem
serial
serial.old
openssl.cnf
private/*
newcerts/*

View File

@@ -1,39 +0,0 @@
#!/bin/bash
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# $1 is the id of the project and $2 is the subject of the cert
NAME=$1
SUBJ=$2
mkdir -p projects/$NAME
cd projects/$NAME
cp ../../openssl.cnf.tmpl openssl.cnf
sed -i -e s/%USERNAME%/$NAME/g openssl.cnf
mkdir certs crl newcerts private
openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf -batch -nodes
echo "10" > serial
touch index.txt
# NOTE(vish): Disabling intermediate ca's because we don't actually need them.
# It makes more sense to have each project have its own root ca.
# openssl genrsa -out private/cakey.pem 1024 -config ./openssl.cnf -batch -nodes
# openssl req -new -sha256 -key private/cakey.pem -out ../../reqs/inter$NAME.csr -batch -subj "$SUBJ"
openssl ca -gencrl -config ./openssl.cnf -out crl.pem
if [ "`id -u`" != "`grep nova /etc/passwd | cut -d':' -f3`" ]; then
sudo chown -R nova:nogroup .
fi
# cd ../../
# openssl ca -extensions v3_ca -days 365 -out INTER/$NAME/cacert.pem -in reqs/inter$NAME.csr -config openssl.cnf -batch

View File

@@ -1,29 +0,0 @@
#!/bin/bash
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
if [ -f "cacert.pem" ];
then
echo "Not installing, it's already done."
else
cp openssl.cnf.tmpl openssl.cnf
sed -i -e s/%USERNAME%/ROOT/g openssl.cnf
openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem -out cacert.pem -days 365 -config ./openssl.cnf -batch -nodes
touch index.txt
echo "10" > serial
openssl ca -gencrl -config ./openssl.cnf -out crl.pem
fi

View File

@@ -1,36 +0,0 @@
#!/bin/bash
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# This gets zipped and run on the cloudpipe-managed OpenVPN server
NAME=$1
SUBJ=$2
mkdir -p projects/$NAME
cd projects/$NAME
# generate a server priv key
openssl genrsa -out server.key 2048
# generate a server CSR
openssl req -new -key server.key -out server.csr -batch -subj "$SUBJ"
novauid=`getent passwd nova | awk -F: '{print $3}'`
if [ ! -z "${novauid}" ] && [ "`id -u`" != "${novauid}" ]; then
sudo chown -R nova:nogroup .
fi

View File

@@ -1,90 +0,0 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# OpenSSL configuration file.
#
# Establish working directory.
dir = .
[ ca ]
default_ca = CA_default
[ CA_default ]
serial = $dir/serial
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/cacert.pem
private_key = $dir/private/cakey.pem
unique_subject = no
default_crl_days = 365
default_days = 365
default_md = md5
preserve = no
email_in_dn = no
nameopt = default_ca
certopt = default_ca
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 1024 # Size of keys
default_keyfile = key.pem # name of generated keys
default_md = md5 # message digest algorithm
string_mask = nombstr # permitted characters
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
# Variable name Prompt string
#---------------------- ----------------------------------
0.organizationName = Organization Name (company)
organizationalUnitName = Organizational Unit Name (department, division)
emailAddress = Email Address
emailAddress_max = 40
localityName = Locality Name (city, district)
stateOrProvinceName = State or Province Name (full name)
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
commonName = Common Name (hostname, IP, or your name)
commonName_max = 64
# Default values for the above, for consistency and less typing.
# Variable name Value
#------------------------------ ------------------------------
0.organizationName_default = NOVA %USERNAME%
localityName_default = Mountain View
stateOrProvinceName_default = California
countryName_default = US
[ v3_ca ]
basicConstraints = CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash

View File

@@ -1 +0,0 @@
*

1
CA/reqs/.gitignore vendored
View File

@@ -1 +0,0 @@
*

View File

View File

@@ -1,7 +1,7 @@
include HACKING LICENSE run_tests.py run_tests.sh include HACKING LICENSE run_tests.py run_tests.sh
include README builddeb.sh exercise_rsapi.py include README builddeb.sh exercise_rsapi.py
include ChangeLog MANIFEST.in pylintrc Authors include ChangeLog MANIFEST.in pylintrc Authors
graft CA graft nova/CA
graft doc graft doc
graft smoketests graft smoketests
graft tools graft tools

View File

@@ -570,6 +570,49 @@ class NetworkCommands(object):
class VmCommands(object): class VmCommands(object):
"""Class for mangaging VM instances.""" """Class for mangaging VM instances."""
def list(self, host=None):
"""Show a list of all instances
:param host: show all instance on specified host.
:param instance: show specificed instance.
"""
print "%-10s %-15s %-10s %-10s %-19s %-12s %-12s %-12s" \
" %-10s %-10s %-10s %-5s" % (
_('instance'),
_('node'),
_('type'),
_('state'),
_('launched'),
_('image'),
_('kernel'),
_('ramdisk'),
_('project'),
_('user'),
_('zone'),
_('index'))
if host == None:
instances = db.instance_get_all(context.get_admin_context())
else:
instances = db.instance_get_all_by_host(
context.get_admin_context(), host)
for instance in instances:
print "%-10s %-15s %-10s %-10s %-19s %-12s %-12s %-12s" \
" %-10s %-10s %-10s %-5d" % (
instance['hostname'],
instance['host'],
instance['instance_type'],
instance['state_description'],
instance['launched_at'],
instance['image_id'],
instance['kernel_id'],
instance['ramdisk_id'],
instance['project_id'],
instance['user_id'],
instance['availability_zone'],
instance['launch_index'])
def live_migration(self, ec2_id, dest): def live_migration(self, ec2_id, dest):
"""Migrates a running instance to a new machine. """Migrates a running instance to a new machine.
@@ -701,15 +744,6 @@ class ServiceCommands(object):
{"method": "update_available_resource"}) {"method": "update_available_resource"})
class LogCommands(object):
def request(self, request_id, logfile='/var/log/nova.log'):
"""Show all fields in the log for the given request. Assumes you
haven't changed the log format too much.
ARGS: request_id [logfile]"""
lines = utils.execute("cat %s | grep '\[%s '" % (logfile, request_id))
print re.sub('#012', "\n", "\n".join(lines))
class DbCommands(object): class DbCommands(object):
"""Class for managing the database.""" """Class for managing the database."""
@@ -725,49 +759,6 @@ class DbCommands(object):
print migration.db_version() print migration.db_version()
class InstanceCommands(object):
"""Class for managing instances."""
def list(self, host=None, instance=None):
"""Show a list of all instances"""
print "%-10s %-15s %-10s %-10s %-19s %-12s %-12s %-12s" \
" %-10s %-10s %-10s %-5s" % (
_('instance'),
_('node'),
_('type'),
_('state'),
_('launched'),
_('image'),
_('kernel'),
_('ramdisk'),
_('project'),
_('user'),
_('zone'),
_('index'))
if host == None:
instances = db.instance_get_all(context.get_admin_context())
else:
instances = db.instance_get_all_by_host(
context.get_admin_context(), host)
for instance in instances:
print "%-10s %-15s %-10s %-10s %-19s %-12s %-12s %-12s" \
" %-10s %-10s %-10s %-5d" % (
instance['hostname'],
instance['host'],
instance['instance_type'],
instance['state_description'],
instance['launched_at'],
instance['image_id'],
instance['kernel_id'],
instance['ramdisk_id'],
instance['project_id'],
instance['user_id'],
instance['availability_zone'],
instance['launch_index'])
class VolumeCommands(object): class VolumeCommands(object):
"""Methods for dealing with a cloud in an odd state""" """Methods for dealing with a cloud in an odd state"""
@@ -878,7 +869,7 @@ class InstanceTypeCommands(object):
elif name == "--all": elif name == "--all":
inst_types = instance_types.get_all_types(True) inst_types = instance_types.get_all_types(True)
else: else:
inst_types = instance_types.get_instance_type(name) inst_types = instance_types.get_instance_type_by_name(name)
except exception.DBError, e: except exception.DBError, e:
_db_error(e) _db_error(e)
if isinstance(inst_types.values()[0], dict): if isinstance(inst_types.values()[0], dict):
@@ -894,20 +885,17 @@ class ImageCommands(object):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.image_service = utils.import_object(FLAGS.image_service) self.image_service = utils.import_object(FLAGS.image_service)
def _register(self, image_type, disk_format, container_format, def _register(self, container_format, disk_format,
path, owner, name=None, is_public='T', path, owner, name=None, is_public='T',
architecture='x86_64', kernel_id=None, ramdisk_id=None): architecture='x86_64', kernel_id=None, ramdisk_id=None):
meta = {'is_public': True, meta = {'is_public': (is_public == 'T'),
'name': name, 'name': name,
'disk_format': disk_format,
'container_format': container_format, 'container_format': container_format,
'disk_format': disk_format,
'properties': {'image_state': 'available', 'properties': {'image_state': 'available',
'owner_id': owner, 'project_id': owner,
'type': image_type,
'architecture': architecture, 'architecture': architecture,
'image_location': 'local', 'image_location': 'local'}}
'is_public': (is_public == 'T')}}
print image_type, meta
if kernel_id: if kernel_id:
meta['properties']['kernel_id'] = int(kernel_id) meta['properties']['kernel_id'] = int(kernel_id)
if ramdisk_id: if ramdisk_id:
@@ -932,16 +920,18 @@ class ImageCommands(object):
ramdisk_id = self.ramdisk_register(ramdisk, owner, None, ramdisk_id = self.ramdisk_register(ramdisk, owner, None,
is_public, architecture) is_public, architecture)
self.image_register(image, owner, name, is_public, self.image_register(image, owner, name, is_public,
architecture, kernel_id, ramdisk_id) architecture, 'ami', 'ami',
kernel_id, ramdisk_id)
def image_register(self, path, owner, name=None, is_public='T', def image_register(self, path, owner, name=None, is_public='T',
architecture='x86_64', kernel_id=None, ramdisk_id=None, architecture='x86_64', container_format='bare',
disk_format='ami', container_format='ami'): disk_format='raw', kernel_id=None, ramdisk_id=None):
"""Uploads an image into the image_service """Uploads an image into the image_service
arguments: path owner [name] [is_public='T'] [architecture='x86_64'] arguments: path owner [name] [is_public='T'] [architecture='x86_64']
[container_format='bare'] [disk_format='raw']
[kernel_id=None] [ramdisk_id=None] [kernel_id=None] [ramdisk_id=None]
[disk_format='ami'] [container_format='ami']""" """
return self._register('machine', disk_format, container_format, path, return self._register(container_format, disk_format, path,
owner, name, is_public, architecture, owner, name, is_public, architecture,
kernel_id, ramdisk_id) kernel_id, ramdisk_id)
@@ -950,7 +940,7 @@ class ImageCommands(object):
"""Uploads a kernel into the image_service """Uploads a kernel into the image_service
arguments: path owner [name] [is_public='T'] [architecture='x86_64'] arguments: path owner [name] [is_public='T'] [architecture='x86_64']
""" """
return self._register('kernel', 'aki', 'aki', path, owner, name, return self._register('aki', 'aki', path, owner, name,
is_public, architecture) is_public, architecture)
def ramdisk_register(self, path, owner, name=None, is_public='T', def ramdisk_register(self, path, owner, name=None, is_public='T',
@@ -958,7 +948,7 @@ class ImageCommands(object):
"""Uploads a ramdisk into the image_service """Uploads a ramdisk into the image_service
arguments: path owner [name] [is_public='T'] [architecture='x86_64'] arguments: path owner [name] [is_public='T'] [architecture='x86_64']
""" """
return self._register('ramdisk', 'ari', 'ari', path, owner, name, return self._register('ari', 'ari', path, owner, name,
is_public, architecture) is_public, architecture)
def _lookup(self, old_image_id): def _lookup(self, old_image_id):
@@ -975,16 +965,17 @@ class ImageCommands(object):
'ramdisk': 'ari'} 'ramdisk': 'ari'}
container_format = mapping[old['type']] container_format = mapping[old['type']]
disk_format = container_format disk_format = container_format
if container_format == 'ami' and not old.get('kernelId'):
container_format = 'bare'
disk_format = 'raw'
new = {'disk_format': disk_format, new = {'disk_format': disk_format,
'container_format': container_format, 'container_format': container_format,
'is_public': True, 'is_public': old['isPublic'],
'name': old['imageId'], 'name': old['imageId'],
'properties': {'image_state': old['imageState'], 'properties': {'image_state': old['imageState'],
'owner_id': old['imageOwnerId'], 'project_id': old['imageOwnerId'],
'architecture': old['architecture'], 'architecture': old['architecture'],
'type': old['type'], 'image_location': old['imageLocation']}}
'image_location': old['imageLocation'],
'is_public': old['isPublic']}}
if old.get('kernelId'): if old.get('kernelId'):
new['properties']['kernel_id'] = self._lookup(old['kernelId']) new['properties']['kernel_id'] = self._lookup(old['kernelId'])
if old.get('ramdiskId'): if old.get('ramdiskId'):
@@ -1049,13 +1040,11 @@ CATEGORIES = [
('network', NetworkCommands), ('network', NetworkCommands),
('vm', VmCommands), ('vm', VmCommands),
('service', ServiceCommands), ('service', ServiceCommands),
('log', LogCommands),
('db', DbCommands), ('db', DbCommands),
('volume', VolumeCommands), ('volume', VolumeCommands),
('instance_type', InstanceTypeCommands), ('instance_type', InstanceTypeCommands),
('image', ImageCommands), ('image', ImageCommands),
('flavor', InstanceTypeCommands), ('flavor', InstanceTypeCommands)]
('instance', InstanceCommands)]
def lazy_match(name, key_value_tuples): def lazy_match(name, key_value_tuples):

View File

@@ -1,473 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Nova User API client library.
"""
import base64
import boto
import boto.exception
import httplib
import re
import string
from boto.ec2.regioninfo import RegionInfo
DEFAULT_CLC_URL = 'http://127.0.0.1:8773'
DEFAULT_REGION = 'nova'
class UserInfo(object):
"""
Information about a Nova user, as parsed through SAX.
**Fields Include**
* username
* accesskey
* secretkey
* file (optional) containing zip of X509 cert & rc file
"""
def __init__(self, connection=None, username=None, endpoint=None):
self.connection = connection
self.username = username
self.endpoint = endpoint
def __repr__(self):
return 'UserInfo:%s' % self.username
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
if name == 'username':
self.username = str(value)
elif name == 'file':
self.file = base64.b64decode(str(value))
elif name == 'accesskey':
self.accesskey = str(value)
elif name == 'secretkey':
self.secretkey = str(value)
class UserRole(object):
"""
Information about a Nova user's role, as parsed through SAX.
**Fields include**
* role
"""
def __init__(self, connection=None):
self.connection = connection
self.role = None
def __repr__(self):
return 'UserRole:%s' % self.role
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
if name == 'role':
self.role = value
else:
setattr(self, name, str(value))
class ProjectInfo(object):
"""
Information about a Nova project, as parsed through SAX.
**Fields include**
* projectname
* description
* projectManagerId
* memberIds
"""
def __init__(self, connection=None):
self.connection = connection
self.projectname = None
self.description = None
self.projectManagerId = None
self.memberIds = []
def __repr__(self):
return 'ProjectInfo:%s' % self.projectname
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
if name == 'projectname':
self.projectname = value
elif name == 'description':
self.description = value
elif name == 'projectManagerId':
self.projectManagerId = value
elif name == 'memberId':
self.memberIds.append(value)
else:
setattr(self, name, str(value))
class ProjectMember(object):
"""
Information about a Nova project member, as parsed through SAX.
**Fields include**
* memberId
"""
def __init__(self, connection=None):
self.connection = connection
self.memberId = None
def __repr__(self):
return 'ProjectMember:%s' % self.memberId
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
if name == 'member':
self.memberId = value
else:
setattr(self, name, str(value))
class HostInfo(object):
"""
Information about a Nova Host, as parsed through SAX.
**Fields Include**
* Hostname
* Compute service status
* Volume service status
* Instance count
* Volume count
"""
def __init__(self, connection=None):
self.connection = connection
self.hostname = None
self.compute = None
self.volume = None
self.instance_count = 0
self.volume_count = 0
def __repr__(self):
return 'Host:%s' % self.hostname
# this is needed by the sax parser, so ignore the ugly name
def startElement(self, name, attrs, connection):
return None
# this is needed by the sax parser, so ignore the ugly name
def endElement(self, name, value, connection):
fixed_name = string.lower(re.sub(r'([A-Z])', r'_\1', name))
setattr(self, fixed_name, value)
class Vpn(object):
"""
Information about a Vpn, as parsed through SAX
**Fields Include**
* instance_id
* project_id
* public_ip
* public_port
* created_at
* internal_ip
* state
"""
def __init__(self, connection=None):
self.connection = connection
self.instance_id = None
self.project_id = None
def __repr__(self):
return 'Vpn:%s:%s' % (self.project_id, self.instance_id)
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
fixed_name = string.lower(re.sub(r'([A-Z])', r'_\1', name))
setattr(self, fixed_name, value)
class InstanceType(object):
"""
Information about a Nova instance type, as parsed through SAX.
**Fields include**
* name
* vcpus
* disk_gb
* memory_mb
* flavor_id
"""
def __init__(self, connection=None):
self.connection = connection
self.name = None
self.vcpus = None
self.disk_gb = None
self.memory_mb = None
self.flavor_id = None
def __repr__(self):
return 'InstanceType:%s' % self.name
def startElement(self, name, attrs, connection):
return None
def endElement(self, name, value, connection):
if name == "memoryMb":
self.memory_mb = str(value)
elif name == "flavorId":
self.flavor_id = str(value)
elif name == "diskGb":
self.disk_gb = str(value)
else:
setattr(self, name, str(value))
class NovaAdminClient(object):
def __init__(
self,
clc_url=DEFAULT_CLC_URL,
region=DEFAULT_REGION,
access_key=None,
secret_key=None,
**kwargs):
parts = self.split_clc_url(clc_url)
self.clc_url = clc_url
self.region = region
self.access = access_key
self.secret = secret_key
self.apiconn = boto.connect_ec2(aws_access_key_id=access_key,
aws_secret_access_key=secret_key,
is_secure=parts['is_secure'],
region=RegionInfo(None,
region,
parts['ip']),
port=parts['port'],
path='/services/Admin',
**kwargs)
self.apiconn.APIVersion = 'nova'
def connection_for(self, username, project, clc_url=None, region=None,
**kwargs):
"""Returns a boto ec2 connection for the given username."""
if not clc_url:
clc_url = self.clc_url
if not region:
region = self.region
parts = self.split_clc_url(clc_url)
user = self.get_user(username)
access_key = '%s:%s' % (user.accesskey, project)
return boto.connect_ec2(aws_access_key_id=access_key,
aws_secret_access_key=user.secretkey,
is_secure=parts['is_secure'],
region=RegionInfo(None,
self.region,
parts['ip']),
port=parts['port'],
path='/services/Cloud',
**kwargs)
def split_clc_url(self, clc_url):
"""Splits a cloud controller endpoint url."""
parts = httplib.urlsplit(clc_url)
is_secure = parts.scheme == 'https'
ip, port = parts.netloc.split(':')
return {'ip': ip, 'port': int(port), 'is_secure': is_secure}
def get_users(self):
"""Grabs the list of all users."""
return self.apiconn.get_list('DescribeUsers', {}, [('item', UserInfo)])
def get_user(self, name):
"""Grab a single user by name."""
user = self.apiconn.get_object('DescribeUser',
{'Name': name},
UserInfo)
if user.username != None:
return user
def has_user(self, username):
"""Determine if user exists."""
return self.get_user(username) != None
def create_user(self, username):
"""Creates a new user, returning the userinfo object with
access/secret."""
return self.apiconn.get_object('RegisterUser', {'Name': username},
UserInfo)
def delete_user(self, username):
"""Deletes a user."""
return self.apiconn.get_object('DeregisterUser', {'Name': username},
UserInfo)
def get_roles(self, project_roles=True):
"""Returns a list of available roles."""
return self.apiconn.get_list('DescribeRoles',
{'ProjectRoles': project_roles},
[('item', UserRole)])
def get_user_roles(self, user, project=None):
"""Returns a list of roles for the given user.
Omitting project will return any global roles that the user has.
Specifying project will return only project specific roles.
"""
params = {'User': user}
if project:
params['Project'] = project
return self.apiconn.get_list('DescribeUserRoles',
params,
[('item', UserRole)])
def add_user_role(self, user, role, project=None):
"""Add a role to a user either globally or for a specific project."""
return self.modify_user_role(user, role, project=project,
operation='add')
def remove_user_role(self, user, role, project=None):
"""Remove a role from a user either globally or for a specific
project."""
return self.modify_user_role(user, role, project=project,
operation='remove')
def modify_user_role(self, user, role, project=None, operation='add',
**kwargs):
"""Add or remove a role for a user and project."""
params = {'User': user,
'Role': role,
'Project': project,
'Operation': operation}
return self.apiconn.get_status('ModifyUserRole', params)
def get_projects(self, user=None):
"""Returns a list of all projects."""
if user:
params = {'User': user}
else:
params = {}
return self.apiconn.get_list('DescribeProjects',
params,
[('item', ProjectInfo)])
def get_project(self, name):
"""Returns a single project with the specified name."""
project = self.apiconn.get_object('DescribeProject',
{'Name': name},
ProjectInfo)
if project.projectname != None:
return project
def create_project(self, projectname, manager_user, description=None,
member_users=None):
"""Creates a new project."""
params = {'Name': projectname,
'ManagerUser': manager_user,
'Description': description,
'MemberUsers': member_users}
return self.apiconn.get_object('RegisterProject', params, ProjectInfo)
def modify_project(self, projectname, manager_user=None, description=None):
"""Modifies an existing project."""
params = {'Name': projectname,
'ManagerUser': manager_user,
'Description': description}
return self.apiconn.get_status('ModifyProject', params)
def delete_project(self, projectname):
"""Permanently deletes the specified project."""
return self.apiconn.get_object('DeregisterProject',
{'Name': projectname},
ProjectInfo)
def get_project_members(self, name):
"""Returns a list of members of a project."""
return self.apiconn.get_list('DescribeProjectMembers',
{'Name': name},
[('item', ProjectMember)])
def add_project_member(self, user, project):
"""Adds a user to a project."""
return self.modify_project_member(user, project, operation='add')
def remove_project_member(self, user, project):
"""Removes a user from a project."""
return self.modify_project_member(user, project, operation='remove')
def modify_project_member(self, user, project, operation='add'):
"""Adds or removes a user from a project."""
params = {'User': user,
'Project': project,
'Operation': operation}
return self.apiconn.get_status('ModifyProjectMember', params)
def get_zip(self, user, project):
"""Returns the content of a zip file containing novarc and access
credentials."""
params = {'Name': user, 'Project': project}
zip = self.apiconn.get_object('GenerateX509ForUser', params, UserInfo)
return zip.file
def start_vpn(self, project):
"""
Starts the vpn for a user
"""
return self.apiconn.get_object('StartVpn', {'Project': project}, Vpn)
def get_vpns(self):
"""Return a list of vpn with project name"""
return self.apiconn.get_list('DescribeVpns', {}, [('item', Vpn)])
def get_hosts(self):
return self.apiconn.get_list('DescribeHosts', {}, [('item', HostInfo)])
def get_instance_types(self):
"""Grabs the list of all users."""
return self.apiconn.get_list('DescribeInstanceTypes', {},
[('item', InstanceType)])

View File

@@ -36,11 +36,13 @@ from nova import rpc
from nova import service from nova import service
from nova import test from nova import test
from nova import utils from nova import utils
from nova import exception
from nova.auth import manager from nova.auth import manager
from nova.compute import power_state from nova.compute import power_state
from nova.api.ec2 import cloud from nova.api.ec2 import cloud
from nova.api.ec2 import ec2utils from nova.api.ec2 import ec2utils
from nova.image import local from nova.image import local
from nova.exception import NotFound
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
@@ -71,7 +73,8 @@ class CloudTestCase(test.TestCase):
host = self.network.get_network_host(self.context.elevated()) host = self.network.get_network_host(self.context.elevated())
def fake_show(meh, context, id): def fake_show(meh, context, id):
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}} return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine'}}
self.stubs.Set(local.LocalImageService, 'show', fake_show) self.stubs.Set(local.LocalImageService, 'show', fake_show)
self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show) self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show)
@@ -216,6 +219,66 @@ class CloudTestCase(test.TestCase):
db.service_destroy(self.context, comp1['id']) db.service_destroy(self.context, comp1['id'])
db.service_destroy(self.context, comp2['id']) db.service_destroy(self.context, comp2['id'])
def test_describe_images(self):
describe_images = self.cloud.describe_images
def fake_detail(meh, context):
return [{'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine'}}]
def fake_show_none(meh, context, id):
raise NotFound
self.stubs.Set(local.LocalImageService, 'detail', fake_detail)
# list all
result1 = describe_images(self.context)
result1 = result1['imagesSet'][0]
self.assertEqual(result1['imageId'], 'ami-00000001')
# provided a valid image_id
result2 = describe_images(self.context, ['ami-00000001'])
self.assertEqual(1, len(result2['imagesSet']))
# provide more than 1 valid image_id
result3 = describe_images(self.context, ['ami-00000001',
'ami-00000002'])
self.assertEqual(2, len(result3['imagesSet']))
# provide an non-existing image_id
self.stubs.UnsetAll()
self.stubs.Set(local.LocalImageService, 'show', fake_show_none)
self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show_none)
self.assertRaises(NotFound, describe_images,
self.context, ['ami-fake'])
def test_describe_image_attribute(self):
describe_image_attribute = self.cloud.describe_image_attribute
def fake_show(meh, context, id):
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine'}, 'is_public': True}
self.stubs.Set(local.LocalImageService, 'show', fake_show)
self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show)
result = describe_image_attribute(self.context, 'ami-00000001',
'launchPermission')
self.assertEqual([{'group': 'all'}], result['launchPermission'])
def test_modify_image_attribute(self):
modify_image_attribute = self.cloud.modify_image_attribute
def fake_show(meh, context, id):
return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine'}, 'is_public': False}
def fake_update(meh, context, image_id, metadata, data=None):
return metadata
self.stubs.Set(local.LocalImageService, 'show', fake_show)
self.stubs.Set(local.LocalImageService, 'show_by_name', fake_show)
self.stubs.Set(local.LocalImageService, 'update', fake_update)
result = modify_image_attribute(self.context, 'ami-00000001',
'launchPermission', 'add',
user_group=['all'])
self.assertEqual(True, result['is_public'])
def test_console_output(self): def test_console_output(self):
instance_type = FLAGS.default_instance_type instance_type = FLAGS.default_instance_type
max_count = 1 max_count = 1
@@ -310,6 +373,19 @@ class CloudTestCase(test.TestCase):
LOG.debug(_("Terminating instance %s"), instance_id) LOG.debug(_("Terminating instance %s"), instance_id)
rv = self.compute.terminate_instance(instance_id) rv = self.compute.terminate_instance(instance_id)
def test_terminate_instances(self):
inst1 = db.instance_create(self.context, {'reservation_id': 'a',
'image_id': 1,
'host': 'host1'})
terminate_instances = self.cloud.terminate_instances
# valid instance_id
result = terminate_instances(self.context, ['i-00000001'])
self.assertTrue(result)
# non-existing instance_id
self.assertRaises(exception.InstanceNotFound, terminate_instances,
self.context, ['i-2'])
db.instance_destroy(self.context, inst1['id'])
def test_update_of_instance_display_fields(self): def test_update_of_instance_display_fields(self):
inst = db.instance_create(self.context, {}) inst = db.instance_create(self.context, {})
ec2_id = ec2utils.id_to_ec2_id(inst['id']) ec2_id = ec2utils.id_to_ec2_id(inst['id'])

View File

@@ -84,7 +84,8 @@ class ComputeTestCase(test.TestCase):
inst['launch_time'] = '10' inst['launch_time'] = '10'
inst['user_id'] = self.user.id inst['user_id'] = self.user.id
inst['project_id'] = self.project.id inst['project_id'] = self.project.id
inst['instance_type'] = 'm1.tiny' type_id = instance_types.get_instance_type_by_name('m1.tiny')['id']
inst['instance_type_id'] = type_id
inst['mac_address'] = utils.generate_mac() inst['mac_address'] = utils.generate_mac()
inst['ami_launch_index'] = 0 inst['ami_launch_index'] = 0
inst.update(params) inst.update(params)
@@ -132,7 +133,7 @@ class ComputeTestCase(test.TestCase):
cases = [dict(), dict(display_name=None)] cases = [dict(), dict(display_name=None)]
for instance in cases: for instance in cases:
ref = self.compute_api.create(self.context, ref = self.compute_api.create(self.context,
FLAGS.default_instance_type, None, **instance) instance_types.get_default_instance_type(), None, **instance)
try: try:
self.assertNotEqual(ref[0]['display_name'], None) self.assertNotEqual(ref[0]['display_name'], None)
finally: finally:
@@ -143,7 +144,7 @@ class ComputeTestCase(test.TestCase):
group = self._create_group() group = self._create_group()
ref = self.compute_api.create( ref = self.compute_api.create(
self.context, self.context,
instance_type=FLAGS.default_instance_type, instance_type=instance_types.get_default_instance_type(),
image_id=None, image_id=None,
security_group=['testgroup']) security_group=['testgroup'])
try: try:
@@ -161,7 +162,7 @@ class ComputeTestCase(test.TestCase):
ref = self.compute_api.create( ref = self.compute_api.create(
self.context, self.context,
instance_type=FLAGS.default_instance_type, instance_type=instance_types.get_default_instance_type(),
image_id=None, image_id=None,
security_group=['testgroup']) security_group=['testgroup'])
try: try:
@@ -177,7 +178,7 @@ class ComputeTestCase(test.TestCase):
ref = self.compute_api.create( ref = self.compute_api.create(
self.context, self.context,
instance_type=FLAGS.default_instance_type, instance_type=instance_types.get_default_instance_type(),
image_id=None, image_id=None,
security_group=['testgroup']) security_group=['testgroup'])
@@ -359,8 +360,9 @@ class ComputeTestCase(test.TestCase):
instance_id = self._create_instance() instance_id = self._create_instance()
self.compute.run_instance(self.context, instance_id) self.compute.run_instance(self.context, instance_id)
inst_type = instance_types.get_instance_type_by_name('m1.xlarge')
db.instance_update(self.context, instance_id, db.instance_update(self.context, instance_id,
{'instance_type': 'm1.xlarge'}) {'instance_type_id': inst_type['id']})
self.assertRaises(exception.ApiError, self.compute_api.resize, self.assertRaises(exception.ApiError, self.compute_api.resize,
context, instance_id, 1) context, instance_id, 1)
@@ -380,8 +382,8 @@ class ComputeTestCase(test.TestCase):
self.compute.terminate_instance(context, instance_id) self.compute.terminate_instance(context, instance_id)
def test_get_by_flavor_id(self): def test_get_by_flavor_id(self):
type = instance_types.get_by_flavor_id(1) type = instance_types.get_instance_type_by_flavor_id(1)
self.assertEqual(type, 'm1.tiny') self.assertEqual(type['name'], 'm1.tiny')
def test_resize_same_source_fails(self): def test_resize_same_source_fails(self):
"""Ensure instance fails to migrate when source and destination are """Ensure instance fails to migrate when source and destination are
@@ -664,4 +666,5 @@ class ComputeTestCase(test.TestCase):
instances = db.instance_get_all(context.get_admin_context()) instances = db.instance_get_all(context.get_admin_context())
LOG.info(_("After force-killing instances: %s"), instances) LOG.info(_("After force-killing instances: %s"), instances)
self.assertEqual(len(instances), 0) self.assertEqual(len(instances), 1)
self.assertEqual(power_state.SHUTOFF, instances[0]['state'])

View File

@@ -62,7 +62,7 @@ class ConsoleTestCase(test.TestCase):
inst['launch_time'] = '10' inst['launch_time'] = '10'
inst['user_id'] = self.user.id inst['user_id'] = self.user.id
inst['project_id'] = self.project.id inst['project_id'] = self.project.id
inst['instance_type'] = 'm1.tiny' inst['instance_type_id'] = 1
inst['mac_address'] = utils.generate_mac() inst['mac_address'] = utils.generate_mac()
inst['ami_launch_index'] = 0 inst['ami_launch_index'] = 0
return db.instance_create(self.context, inst)['id'] return db.instance_create(self.context, inst)['id']

View File

@@ -40,7 +40,11 @@ class InstanceTypeTestCase(test.TestCase):
max_flavorid = session.query(models.InstanceTypes).\ max_flavorid = session.query(models.InstanceTypes).\
order_by("flavorid desc").\ order_by("flavorid desc").\
first() first()
max_id = session.query(models.InstanceTypes).\
order_by("id desc").\
first()
self.flavorid = max_flavorid["flavorid"] + 1 self.flavorid = max_flavorid["flavorid"] + 1
self.id = max_id["id"] + 1
self.name = str(int(time.time())) self.name = str(int(time.time()))
def test_instance_type_create_then_delete(self): def test_instance_type_create_then_delete(self):
@@ -53,7 +57,7 @@ class InstanceTypeTestCase(test.TestCase):
'instance type was not created') 'instance type was not created')
instance_types.destroy(self.name) instance_types.destroy(self.name)
self.assertEqual(1, self.assertEqual(1,
instance_types.get_instance_type(self.name)["deleted"]) instance_types.get_instance_type(self.id)["deleted"])
self.assertEqual(starting_inst_list, instance_types.get_all_types()) self.assertEqual(starting_inst_list, instance_types.get_all_types())
instance_types.purge(self.name) instance_types.purge(self.name)
self.assertEqual(len(starting_inst_list), self.assertEqual(len(starting_inst_list),

View File

@@ -263,7 +263,7 @@ class SimpleDriverTestCase(test.TestCase):
inst['reservation_id'] = 'r-fakeres' inst['reservation_id'] = 'r-fakeres'
inst['user_id'] = self.user.id inst['user_id'] = self.user.id
inst['project_id'] = self.project.id inst['project_id'] = self.project.id
inst['instance_type'] = 'm1.tiny' inst['instance_type_id'] = '1'
inst['mac_address'] = utils.generate_mac() inst['mac_address'] = utils.generate_mac()
inst['vcpus'] = kwargs.get('vcpus', 1) inst['vcpus'] = kwargs.get('vcpus', 1)
inst['ami_launch_index'] = 0 inst['ami_launch_index'] = 0

View File

@@ -140,7 +140,7 @@ class LibvirtConnTestCase(test.TestCase):
'vcpus': 2, 'vcpus': 2,
'project_id': 'fake', 'project_id': 'fake',
'bridge': 'br101', 'bridge': 'br101',
'instance_type': 'm1.small'} 'instance_type_id': '5'} # m1.small
def lazy_load_library_exists(self): def lazy_load_library_exists(self):
"""check if libvirt is available.""" """check if libvirt is available."""
@@ -479,7 +479,7 @@ class LibvirtConnTestCase(test.TestCase):
fake_timer = FakeTime() fake_timer = FakeTime()
self.create_fake_libvirt_mock(nwfilterLookupByName=fake_raise) self.create_fake_libvirt_mock()
instance_ref = db.instance_create(self.context, self.test_instance) instance_ref = db.instance_create(self.context, self.test_instance)
# Start test # Start test
@@ -488,6 +488,7 @@ class LibvirtConnTestCase(test.TestCase):
conn = libvirt_conn.LibvirtConnection(False) conn = libvirt_conn.LibvirtConnection(False)
conn.firewall_driver.setattr('setup_basic_filtering', fake_none) conn.firewall_driver.setattr('setup_basic_filtering', fake_none)
conn.firewall_driver.setattr('prepare_instance_filter', fake_none) conn.firewall_driver.setattr('prepare_instance_filter', fake_none)
conn.firewall_driver.setattr('instance_filter_exists', fake_none)
conn.ensure_filtering_rules_for_instance(instance_ref, conn.ensure_filtering_rules_for_instance(instance_ref,
time=fake_timer) time=fake_timer)
except exception.Error, e: except exception.Error, e:

View File

@@ -106,7 +106,7 @@ class VolumeTestCase(test.TestCase):
inst['launch_time'] = '10' inst['launch_time'] = '10'
inst['user_id'] = 'fake' inst['user_id'] = 'fake'
inst['project_id'] = 'fake' inst['project_id'] = 'fake'
inst['instance_type'] = 'm1.tiny' inst['instance_type_id'] = '2' # m1.tiny
inst['mac_address'] = utils.generate_mac() inst['mac_address'] = utils.generate_mac()
inst['ami_launch_index'] = 0 inst['ami_launch_index'] = 0
instance_id = db.instance_create(self.context, inst)['id'] instance_id = db.instance_create(self.context, inst)['id']

View File

@@ -80,7 +80,7 @@ class XenAPIVolumeTestCase(test.TestCase):
'image_id': 1, 'image_id': 1,
'kernel_id': 2, 'kernel_id': 2,
'ramdisk_id': 3, 'ramdisk_id': 3,
'instance_type': 'm1.large', 'instance_type_id': '3', # m1.large
'mac_address': 'aa:bb:cc:dd:ee:ff', 'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': 'linux'} 'os_type': 'linux'}
@@ -289,11 +289,11 @@ class XenAPIVMTestCase(test.TestCase):
'enabled':'1'}], 'enabled':'1'}],
'ip6s': [{'ip': 'fe80::a8bb:ccff:fedd:eeff', 'ip6s': [{'ip': 'fe80::a8bb:ccff:fedd:eeff',
'netmask': '120', 'netmask': '120',
'enabled': '1', 'enabled': '1'}],
'gateway': 'fe80::a00:1'}],
'mac': 'aa:bb:cc:dd:ee:ff', 'mac': 'aa:bb:cc:dd:ee:ff',
'dns': ['10.0.0.2'], 'dns': ['10.0.0.2'],
'gateway': '10.0.0.1'}) 'gateway': '10.0.0.1',
'gateway6': 'fe80::a00:1'})
def check_vm_params_for_windows(self): def check_vm_params_for_windows(self):
self.assertEquals(self.vm['platform']['nx'], 'true') self.assertEquals(self.vm['platform']['nx'], 'true')
@@ -328,7 +328,7 @@ class XenAPIVMTestCase(test.TestCase):
self.assertEquals(self.vm['HVM_boot_policy'], '') self.assertEquals(self.vm['HVM_boot_policy'], '')
def _test_spawn(self, image_id, kernel_id, ramdisk_id, def _test_spawn(self, image_id, kernel_id, ramdisk_id,
instance_type="m1.large", os_type="linux", instance_type_id="3", os_type="linux",
instance_id=1, check_injection=False): instance_id=1, check_injection=False):
stubs.stubout_loopingcall_start(self.stubs) stubs.stubout_loopingcall_start(self.stubs)
values = {'id': instance_id, values = {'id': instance_id,
@@ -337,7 +337,7 @@ class XenAPIVMTestCase(test.TestCase):
'image_id': image_id, 'image_id': image_id,
'kernel_id': kernel_id, 'kernel_id': kernel_id,
'ramdisk_id': ramdisk_id, 'ramdisk_id': ramdisk_id,
'instance_type': instance_type, 'instance_type_id': instance_type_id,
'mac_address': 'aa:bb:cc:dd:ee:ff', 'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': os_type} 'os_type': os_type}
instance = db.instance_create(self.context, values) instance = db.instance_create(self.context, values)
@@ -349,7 +349,7 @@ class XenAPIVMTestCase(test.TestCase):
FLAGS.xenapi_image_service = 'glance' FLAGS.xenapi_image_service = 'glance'
self.assertRaises(Exception, self.assertRaises(Exception,
self._test_spawn, self._test_spawn,
1, 2, 3, "m1.xlarge") 1, 2, 3, "4") # m1.xlarge
def test_spawn_raw_objectstore(self): def test_spawn_raw_objectstore(self):
FLAGS.xenapi_image_service = 'objectstore' FLAGS.xenapi_image_service = 'objectstore'
@@ -523,7 +523,7 @@ class XenAPIVMTestCase(test.TestCase):
'image_id': 1, 'image_id': 1,
'kernel_id': 2, 'kernel_id': 2,
'ramdisk_id': 3, 'ramdisk_id': 3,
'instance_type': 'm1.large', 'instance_type_id': '3', # m1.large
'mac_address': 'aa:bb:cc:dd:ee:ff', 'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': 'linux'} 'os_type': 'linux'}
instance = db.instance_create(self.context, values) instance = db.instance_create(self.context, values)
@@ -580,7 +580,7 @@ class XenAPIMigrateInstance(test.TestCase):
'kernel_id': None, 'kernel_id': None,
'ramdisk_id': None, 'ramdisk_id': None,
'local_gb': 5, 'local_gb': 5,
'instance_type': 'm1.large', 'instance_type_id': '3', # m1.large
'mac_address': 'aa:bb:cc:dd:ee:ff', 'mac_address': 'aa:bb:cc:dd:ee:ff',
'os_type': 'linux'} 'os_type': 'linux'}

3888
po/ast.po

File diff suppressed because it is too large Load Diff

3915
po/cs.po

File diff suppressed because it is too large Load Diff

3892
po/da.po

File diff suppressed because it is too large Load Diff

3978
po/de.po

File diff suppressed because it is too large Load Diff

4732
po/es.po

File diff suppressed because it is too large Load Diff

4077
po/it.po

File diff suppressed because it is too large Load Diff

4662
po/ja.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4055
po/ru.po

File diff suppressed because it is too large Load Diff

3935
po/uk.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff